//package com.yvon.boot.mybatis.support;
//
//import com.baomidou.mybatisplus.annotation.DbType;
//import com.baomidou.mybatisplus.core.MybatisDefaultParameterHandler;
//import com.baomidou.mybatisplus.core.metadata.IPage;
//import com.baomidou.mybatisplus.core.metadata.OrderItem;
//import com.baomidou.mybatisplus.core.parser.ISqlParser;
//import com.baomidou.mybatisplus.core.parser.SqlInfo;
//import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
//import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
//import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
//import com.baomidou.mybatisplus.core.toolkit.StringUtils;
//import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
//import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
//import com.baomidou.mybatisplus.extension.plugins.pagination.DialectFactory;
//import com.baomidou.mybatisplus.extension.plugins.pagination.DialectModel;
//import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
//import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils;
//import lombok.extern.slf4j.Slf4j;
//import net.sf.jsqlparser.JSQLParserException;
//import net.sf.jsqlparser.parser.CCJSqlParserUtil;
//import net.sf.jsqlparser.schema.Column;
//import net.sf.jsqlparser.statement.select.*;
//import org.apache.ibatis.executor.statement.StatementHandler;
//import org.apache.ibatis.mapping.*;
//import org.apache.ibatis.plugin.Intercepts;
//import org.apache.ibatis.plugin.Invocation;
//import org.apache.ibatis.plugin.Plugin;
//import org.apache.ibatis.plugin.Signature;
//import org.apache.ibatis.reflection.MetaObject;
//import org.apache.ibatis.reflection.SystemMetaObject;
//import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
//import org.apache.ibatis.session.Configuration;
//
//import java.lang.reflect.InvocationTargetException;
//import java.sql.Connection;
//import java.sql.PreparedStatement;
//import java.sql.ResultSet;
//import java.util.*;
//
///**
// * 分页拦截器
// *
// * @author : Yvon
// * @since : 2021-09-03
// */
//@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
//@Slf4j
//public class SortPaginationInterceptor extends MybatisPlusInterceptor {
//
//    private ISqlParser countSqlParser;
//    private boolean overflow = false;
//    private long limit = 500L;
//    private String dialectType;
//    private String dialectClazz;
//
//    public SortPaginationInterceptor() {
//    }
//
//    public static String concatOrderBy(String originalSql, IPage<?> page) {
//        if (CollectionUtils.isNotEmpty(page.orders())) {
//            try {
//                List<OrderItem> orderList = page.orders();
//                Select selectStatement = (Select) CCJSqlParserUtil.parse(originalSql);
//                List orderByElements;
//                List orderByElementsReturn;
//                if (selectStatement.getSelectBody() instanceof PlainSelect) {
//                    PlainSelect plainSelect = (PlainSelect)selectStatement.getSelectBody();
//                    orderByElements = plainSelect.getOrderByElements();
//                    orderByElementsReturn = addOrderByElements(orderList, orderByElements);
//                    plainSelect.setOrderByElements(orderByElementsReturn);
//                    return plainSelect.toString();
//                }
//
//                if (selectStatement.getSelectBody() instanceof SetOperationList) {
//                    SetOperationList setOperationList = (SetOperationList)selectStatement.getSelectBody();
//                    orderByElements = setOperationList.getOrderByElements();
//                    orderByElementsReturn = addOrderByElements(orderList, orderByElements);
//                    setOperationList.setOrderByElements(orderByElementsReturn);
//                    return setOperationList.toString();
//                }
//
//                if (selectStatement.getSelectBody() instanceof WithItem) {
//                    return originalSql;
//                }
//
//                return originalSql;
//            } catch (JSQLParserException var7) {
//            }
//        }
//
//        return originalSql;
//    }
//
//    private static List<OrderByElement> addOrderByElements(List<OrderItem> orderList, List<OrderByElement> orderByElements) {
//        if (orderByElements == null || ((List)orderByElements).isEmpty()) {
//            orderByElements = new ArrayList(orderList.size());
//        }
//
//        Iterator var2 = orderList.iterator();
//
//        while(var2.hasNext()) {
//            OrderItem item = (OrderItem)var2.next();
//            OrderByElement element = new OrderByElement();
//            element.setExpression(new Column(item.getColumn()));
//            element.setAsc(item.isAsc());
//            ((List)orderByElements).add(element);
//        }
//
//        return (List)orderByElements;
//    }
//
//    @Override
//    public Object intercept(Invocation invocation) throws Throwable {
//        StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
//        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
//        this.sqlParser(metaObject);
//        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
//        if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType() && StatementType.CALLABLE != mappedStatement.getStatementType()) {
//            BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
//            Object paramObj = boundSql.getParameterObject();
//            IPage<?> page = null;
//            if (paramObj instanceof IPage) {
//                page = (IPage)paramObj;
//            } else if (paramObj instanceof Map) {
//                Iterator var8 = ((Map)paramObj).values().iterator();
//
//                while(var8.hasNext()) {
//                    Object arg = var8.next();
//                    if (arg instanceof IPage) {
//                        page = (IPage)arg;
//                        break;
//                    }
//                }
//            }
//
//            if (null == page) {
//                return invocation.proceed();
//            } else if (page.getSize() < 0L) {
//                return this.orderIntercept(page, invocation, metaObject, boundSql);
//            } else {
//                if (this.limit > 0L && this.limit <= page.getSize()) {
//                    page.setSize(this.limit);
//                }
//
//                String originalSql = boundSql.getSql();
//                Connection connection = (Connection)invocation.getArgs()[0];
//                DbType dbType = StringUtils.isNotEmpty(this.dialectType) ? DbType.getDbType(this.dialectType) : JdbcUtils.getDbType(connection.getMetaData().getURL());
//                if (page.isSearchCount()) {
//                    SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(page.optimizeCountSql(), this.countSqlParser, originalSql);
//                    this.queryTotal(this.overflow, sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
//                    if (page.getTotal() <= 0L) {
//                        return null;
//                    }
//                }
//
//                String buildSql = concatOrderBy(originalSql, page);
//                DialectModel model = DialectFactory.buildPaginationSql(page, buildSql, dbType, this.dialectClazz);
//                Configuration configuration = mappedStatement.getConfiguration();
//                List<ParameterMapping> mappings = new ArrayList(boundSql.getParameterMappings());
//                Map<String, Object> additionalParameters = (Map)metaObject.getValue("delegate.boundSql.additionalParameters");
//                model.consumers(mappings, configuration, additionalParameters);
//                metaObject.setValue("delegate.boundSql.sql", model.getDialectSql());
//                metaObject.setValue("delegate.boundSql.parameterMappings", mappings);
//                return invocation.proceed();
//            }
//        } else {
//            return invocation.proceed();
//        }
//    }
//
//    @Override
//    protected void queryTotal(boolean overflowCurrent, String sql, MappedStatement mappedStatement, BoundSql boundSql, IPage<?> page, Connection connection) {
//        try {
//            PreparedStatement statement = connection.prepareStatement(sql);
//            Throwable var8 = null;
//
//            try {
//                DefaultParameterHandler parameterHandler = new MybatisDefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql);
//                parameterHandler.setParameters(statement);
//                long total = 0L;
//                ResultSet resultSet = statement.executeQuery();
//                Throwable var13 = null;
//
//                try {
//                    if (resultSet.next()) {
//                        total = resultSet.getLong(1);
//                    }
//                } catch (Throwable var38) {
//                    var13 = var38;
//                    throw var38;
//                } finally {
//                    if (resultSet != null) {
//                        if (var13 != null) {
//                            try {
//                                resultSet.close();
//                            } catch (Throwable var37) {
//                                var13.addSuppressed(var37);
//                            }
//                        } else {
//                            resultSet.close();
//                        }
//                    }
//
//                }
//
//                page.setTotal(total);
//                long pages = page.getPages();
//                if (overflowCurrent && page.getCurrent() > pages) {
//                    page.setCurrent(1L);
//                }
//            } catch (Throwable var40) {
//                var8 = var40;
//                throw var40;
//            } finally {
//                if (statement != null) {
//                    if (var8 != null) {
//                        try {
//                            statement.close();
//                        } catch (Throwable var36) {
//                            var8.addSuppressed(var36);
//                        }
//                    } else {
//                        statement.close();
//                    }
//                }
//
//            }
//
//        } catch (Exception var42) {
//            throw ExceptionUtils.mpe("Error: Method queryTotal execution error of sql : \n %s \n", var42, new Object[]{sql});
//        }
//    }
//
//    @Override
//    public Object plugin(Object target) {
//        return target instanceof StatementHandler ? Plugin.wrap(target, this) : target;
//    }
//
//    @Override
//    public void setProperties(Properties prop) {
//        String dialectType = prop.getProperty("dialectType");
//        String dialectClazz = prop.getProperty("dialectClazz");
//        if (StringUtils.isNotEmpty(dialectType)) {
//            this.dialectType = dialectType;
//        }
//
//        if (StringUtils.isNotEmpty(dialectClazz)) {
//            this.dialectClazz = dialectClazz;
//        }
//
//    }
//
//    private Object orderIntercept(IPage<?> page, Invocation invocation, MetaObject metaObject, BoundSql boundSql) throws InvocationTargetException, IllegalAccessException {
//        String originalSql = boundSql.getSql();
//        String buildSql = concatOrderBy(originalSql, page);
//        metaObject.setValue("delegate.boundSql.sql", buildSql);
//        return invocation.proceed();
//    }
//
//    @Override
//    public SortPaginationInterceptor setCountSqlParser(ISqlParser countSqlParser) {
//        this.countSqlParser = countSqlParser;
//        return this;
//    }
//
//    @Override
//    public SortPaginationInterceptor setOverflow(boolean overflow) {
//        this.overflow = overflow;
//        return this;
//    }
//
//    @Override
//    public SortPaginationInterceptor setLimit(long limit) {
//        this.limit = limit;
//        return this;
//    }
//
//    @Override
//    public SortPaginationInterceptor setDialectType(String dialectType) {
//        this.dialectType = dialectType;
//        return this;
//    }
//
//    @Override
//    public SortPaginationInterceptor setDialectClazz(String dialectClazz) {
//        this.dialectClazz = dialectClazz;
//        return this;
//    }
//}
